package controllers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import models.CalificacionPeriodo;
import models.CategoriasIndicadores;
import models.Curso;
import models.Estudiante;
import models.Grado;
import models.Indicador;
import models.IndicadorPeriodo;
import models.IndicadorPeriodoId;
import models.IndicadorId;
import models.Materia;
import models.MateriaCurso;
import models.MensajeEstudiante;
import play.db.jpa.Transactional;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import services.ColegioSrv;
import services.DAO;
import services.ProfesorSrv;
import util.annotations.NamedAction;

public class ProfesorCtrl extends Controller {

	private static long getIdColegio() {
		return Long.parseLong(session("idColegio"));
	}

	private static long getIdProfesor() {
		return Long.parseLong(session(UserCtrl.ACTOR_ID_KEY));
	}

	@Transactional(readOnly = true)
	@NamedAction("getMisAsignaturas")
	public static Result getMisAsignaturas() {

		List<MateriaCurso> asignaturas = ProfesorSrv.getAsignaturasProfesor(
				getIdProfesor(), ColegioSrv.getColegio(getIdColegio())
						.getIdCalendarioAcademicoActual());

		return ok(Json.toJson(asignaturas));
	}

	@Transactional(readOnly = true)
	@NamedAction("read")
	public static Result getCalificacionesPeriodo(Long idMateria, Long idCurso) {

		return ok(Json.toJson(ProfesorSrv.getCalificacionesPeriodo(idMateria,
				idCurso, ColegioSrv.getColegio(getIdColegio())
						.getIdCalendarioAcademicoActual())));
	}

	@Transactional(readOnly = true)
	@NamedAction("read")
	public static Result getMateriasGrado() {
		return ok(Json.toJson(ProfesorSrv.getMateriasGrado(getIdColegio(),
				getIdProfesor())));
	}

	@Transactional(readOnly = true)
	@NamedAction("getIndicadores")
	public static Result getIndicadoresPeriodoActual(Long idMateria, Long idGrado) {
		Long idPeriodo = ColegioSrv.getColegio(getIdColegio()).getIdPeriodoActual();
		List<Indicador> inds = DAO
				.execute(
						"SELECT i FROM Indicador i WHERE i.idMateria = :idMateria AND i.idGrado = :idGrado AND i.idPeriodo = :idPeriodo",
						-1, "idMateria", idMateria, "idGrado", idGrado,
						"idPeriodo", idPeriodo);

		Map<CategoriasIndicadores, List<Indicador>> indicadores = new HashMap<CategoriasIndicadores, List<Indicador>>();
		for (CategoriasIndicadores c : CategoriasIndicadores.values())
			indicadores.put(c, new ArrayList<Indicador>());

		for (Indicador i : inds)
			indicadores.get(i.getCategoria()).add(i);
		return ok(Json.toJson(inds));
	}

	@Transactional
	@NamedAction("newIndicador")
	public static Result newIndicadorPeriodoActual(Long idMateria, Long idGrado) {
		Long idPeriodo = ColegioSrv.getColegio(getIdColegio()).getIdPeriodoActual();
		if (!checkColegio(idMateria, idGrado))
			return unauthorized();
		Indicador i = Json.fromJson(request().body().asJson(), Indicador.class);
		i.setIdMateria(idMateria);
		i.setIdGrado(idGrado);
		i.setIdPeriodo(idPeriodo);

		i.generateConsecutivo();
		DAO.persist(i);
		return ok(Json.toJson(i));
	}

	@Transactional
	@NamedAction("updateIndicador")
	public static Result updateIndicador(Long idMateria, Long idGrado,
			String categoria, Integer consecutivo) {
		if (!checkColegio(idMateria, idGrado))
			return unauthorized();
		Long idPeriodo = ColegioSrv.getColegio(getIdColegio()).getIdPeriodoActual();
		Indicador i = Json.fromJson(request().body().asJson(), Indicador.class);
		i.setIdPeriodo(idPeriodo);
		DAO.merge(i);
		return ok();
	}

	@Transactional
	@NamedAction("deleteIndicador")
	public static Result deleteIndicador(Long idMateria, Long idGrado,
			String categoria, Integer consecutivo) {
		if (!checkColegio(idMateria, idGrado))
			return unauthorized();

		Long idPeriodo = ColegioSrv.getColegio(getIdColegio()).getIdPeriodoActual();
		Indicador old = DAO.find(Indicador.class, new IndicadorId(idMateria,
				idGrado, idPeriodo, CategoriasIndicadores.valueOf(categoria),
				consecutivo));

		if (old != null)
			DAO.remove(old);
		return ok();
	}

	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	@NamedAction("read")
	public static Result getCurso(Long idCurso) {
		Curso curso = DAO.find(Curso.class, idCurso);
		curso.setEstudiantes((List<Estudiante>) DAO
				.execute(
						"SELECT e FROM Estudiante e, Matricula m WHERE m.idEstudiante = e.id AND m.idCurso = :idCurso",
						-1, "idCurso", curso.getId()));
		return ok(Json.toJson(curso));
	}

	@Transactional(readOnly = true)
	@NamedAction("getIndicadoresEstudiantes")
	public static Result getIndicadoresEstudiantes(Long idCurso, Long idMateria) {
		Curso curso = DAO.find(Curso.class, idCurso);
		Long idPeriodoActual = ColegioSrv.getColegio(getIdColegio())
				.getIdPeriodoActual();
		List<IndicadorPeriodo> res = DAO
				.execute(
						"SELECT c FROM IndicadorPeriodo c WHERE c.idMateria = :idMateria AND c.idGrado = :idGrado AND c.idPeriodo = :idPeriodo",
						-1, "idMateria", idMateria, "idGrado",
						curso.getIdGrado(), "idPeriodo", idPeriodoActual);
		return ok(Json.toJson(res));
	}

	@Transactional
	@NamedAction("newIndicadorEstudiante")
	public static Result newIndicadorEstudiante() {
		IndicadorPeriodo ic = Json.fromJson(request().body().asJson(),
				IndicadorPeriodo.class);
		ic.setIdPeriodo(ColegioSrv.getColegio(getIdColegio()).getIdPeriodoActual());
		DAO.merge(ic);
		return ok(Json.toJson(ic));
	}

	@Transactional
	@NamedAction("deleteIndicadorEstudiante")
	public static Result deleteIndicadorEstudiante(Long idEstudiante,
			Long idMateria, Long idGrado, String categoriaIndicador,
			Integer consecutivoIndicador) {
		Long idPeriodoActual = ColegioSrv.getColegio(getIdColegio())
				.getIdPeriodoActual();
		IndicadorPeriodoId id = new IndicadorPeriodoId(idEstudiante, idMateria,
				idGrado, idPeriodoActual,
				CategoriasIndicadores.valueOf(categoriaIndicador),
				consecutivoIndicador);
		IndicadorPeriodo ic = DAO.find(IndicadorPeriodo.class, id);
		DAO.remove(ic);
		return ok();
	}

	@Transactional
	@NamedAction("setCalificacionPeriodo")
	public static Result setCalificacionPeriodo() {
		CalificacionPeriodo ic = Json.fromJson(request().body().asJson(),
				CalificacionPeriodo.class);
		ic.setIdPeriodo(ColegioSrv.getColegio(getIdColegio()).getIdPeriodoActual());
		DAO.merge(ic);
		return ok(Json.toJson(ic));
	}

	@Transactional
	@NamedAction("sendMessage")
	public static Result sendMessage() {
		MensajeEstudiante me = Json.fromJson(request().body().asJson(),
				MensajeEstudiante.class);
		me.setIdProfesor(Long.parseLong(session(UserCtrl.ACTOR_ID_KEY)));
		DAO.persist(me);
		return ok();
	}

	@Transactional(readOnly = true)
	@NamedAction("read")
	public static Result getMaterias() {
		return ok(Json.toJson(ColegioSrv.getMateriasColegio(getIdColegio())));
	}

	@Transactional(readOnly = true)
	@NamedAction("read")
	public static Result getGrados() {

		return ok(Json.toJson(ColegioSrv.getGradosColegio(getIdColegio())));
	}

	private static boolean checkColegio(Long idMateria, Long idGrado) {
		Materia m = DAO.find(Materia.class, idMateria);
		if (m == null || !m.getIdColegio().equals(getIdColegio()))
			return false;
		Grado g = DAO.find(Grado.class, idGrado);
		if (g == null || !g.getIdColegio().equals(getIdColegio()))
			return false;
		return true;
	}
}
